import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { ComponentPropsType } from "@/components/QuestionComponents";
import { produce } from "immer";
import { getNextSelectId, inserNewComponent } from "./utils";
import { cloneDeep } from "lodash";
import { nanoid } from "nanoid";

import { arrayMove } from "@dnd-kit/sortable";

export type ComponentInfoType = {
  fe_id: string;
  type: string;
  title: string;
  isHidden?: boolean;
  isLocked?: boolean;
  props: ComponentPropsType;
};

export type ComponentStateType = {
  selectId: string;
  componentList: ComponentInfoType[];
  copiedComponent?: ComponentInfoType | null;
};

const INIT_STATE: ComponentStateType = {
  selectId: "",
  componentList: [],
  //扩展
  copiedComponent: void 0,
};

export const componentSlice = createSlice({
  name: "components",
  initialState: INIT_STATE,
  reducers: {
    //重置所有组件
    resetComponents: (
      state: ComponentStateType,
      action: PayloadAction<ComponentStateType>
    ) => {
      return action.payload;
    },
    //修改 selectID 选中组件
    changeSelectId: produce(
      (draft: ComponentStateType, action: PayloadAction<string>) => {
        draft.selectId = action.payload;
      }
    ),
    //添加新组件
    addComponent: produce(
      (draft: ComponentStateType, action: PayloadAction<ComponentInfoType>) => {
        const newComponent = action.payload;
        inserNewComponent(draft, newComponent);
      }
    ),
    // 修改组件属性
    changeComponentProps: produce(
      (
        draft: ComponentStateType,
        action: PayloadAction<{ fe_id: string; newProps: ComponentPropsType }>
      ) => {
        const { fe_id, newProps } = action.payload;

        const curComp = draft.componentList.find((c) => c.fe_id === fe_id);
        if (curComp) {
          curComp.props = {
            ...curComp.props,
            ...newProps,
          };
        }
      }
    ),
    //删除选中的组件
    removeSelectedComponent: produce((draft: ComponentStateType) => {
      const { componentList = [], selectId: removedId } = draft;

      const index = componentList.findIndex((c) => c.fe_id === removedId);

      const newSelectedId = getNextSelectId(componentList, removedId);
      draft.selectId = newSelectedId;

      componentList.splice(index, 1);
    }),
    //隐藏组件
    changeComponentHidden: produce(
      (
        draft: ComponentStateType,
        action: PayloadAction<{ fe_id: string; isHidden: boolean }>
      ) => {
        const { componentList = [] } = draft;
        const { fe_id, isHidden } = action.payload;
        let newSelectedId = "";
        // 要隐藏组件，就计算，要显示就直接给id
        if (isHidden) {
          newSelectedId = getNextSelectId(componentList, fe_id);
        } else {
          newSelectedId = fe_id;
        }
        draft.selectId = newSelectedId;
        const curComp = componentList.find((c) => c.fe_id === fe_id);
        if (curComp) {
          curComp.isHidden = isHidden;
        }
      }
    ),
    //锁定/解锁组件
    toggleComponentLocked: produce(
      (draft: ComponentStateType, action: PayloadAction<{ fe_id: string }>) => {
        const { fe_id } = action.payload;
        const curComp = draft.componentList.find((c) => c.fe_id === fe_id);
        if (curComp) {
          curComp.isLocked = !curComp.isLocked;
        }
      }
    ),
    // 复制组件
    copiedComponent: produce((draft: ComponentStateType) => {
      const curComp = draft.componentList.find(
        (c) => c.fe_id === draft.selectId
      );
      if (curComp) {
        draft.copiedComponent = cloneDeep(curComp);
      }
    }),
    //粘贴
    pasteComponent: produce((draft: ComponentStateType) => {
      const { copiedComponent } = draft;
      if (!copiedComponent) return;
      const newComponent = cloneDeep(copiedComponent);
      newComponent.fe_id = nanoid();
      inserNewComponent(draft, newComponent);
    }),
    //选中上一个
    selectPrevComponent: produce((draft: ComponentStateType) => {
      const { selectId, componentList } = draft;
      const selectIndex = componentList.findIndex((c) => c.fe_id === selectId);
      if (selectIndex < 0) return; // 未选中组件
      if (selectIndex <= 0) return; //选中了第一个无法向上选中
      draft.selectId = componentList[selectIndex - 1].fe_id;
    }),
    //选中下一个
    selectNextComponent: produce((draft: ComponentStateType) => {
      const { selectId, componentList } = draft;
      const selectIndex = componentList.findIndex((c) => c.fe_id === selectId);
      if (selectIndex < 0) return; // 未选中组件
      if (selectIndex >= componentList.length - 1) return; //选中了第一个无法向上选中
      draft.selectId = componentList[selectIndex + 1].fe_id;
    }),
    //更新标题
    changeComponentTitle: produce(
      (draft: ComponentStateType, action: PayloadAction<{ title: string }>) => {
        const { selectId, componentList } = draft;
        const curComp = componentList.find((c) => c.fe_id === selectId);
        if (curComp) {
          curComp.title = action.payload.title;
        }
      }
    ),
    //移动组件位置
    moveComponent: produce(
      (
        draft: ComponentStateType,
        actions: PayloadAction<{ oldIndex: number; newIndex: number }>
      ) => {
        const { oldIndex, newIndex } = actions.payload;
        draft.componentList = arrayMove(
          draft.componentList,
          oldIndex,
          newIndex
        );
      }
    ),
  },
});

export const {
  resetComponents,
  changeSelectId,
  addComponent,
  changeComponentProps,
  removeSelectedComponent,
  changeComponentHidden,
  toggleComponentLocked,
  copiedComponent,
  pasteComponent,
  selectPrevComponent,
  selectNextComponent,
  changeComponentTitle,
  moveComponent,
} = componentSlice.actions;

export default componentSlice.reducer;
